
#include "Transform.hpp"

using namespace Typhoon;

Transform::Transform()
	:
Position(this),
Rotation(this),
Anchor(this),
Matrix(this),
Local(this),
World(this),
WorldInverse(this)
{
	Position.Changed+=event_handler(this, &Transform::PropertyChanged);
	Rotation.Changed+=event_handler(this, &Transform::PropertyChanged);
	Anchor.Changed+=event_handler(this, &Transform::PropertyChanged);
	Matrix.Changed+=event_handler(this, &Transform::PropertyChanged);

	Matrix = Matrix4x4::IDENTITY;

	Local.Method += event_handler(this, &Transform::CalcLocal);
	World.Method += event_handler(this, &Transform::CalcWorld);
	WorldInverse.Method += event_handler(this, &Transform::CalcWorldInverse);
}

void Transform::PropertyChanged(Transform* transform) {
	Local.MakeDirty();
	World.MakeDirty();
	WorldInverse.MakeDirty();
}

void Transform::CalcLocal( DirtyProperty<Transform*, Matrix4x4>::EventData& event )
{
	Matrix4x4& local = *event.Value;
	Matrix4x4 rotation;
	Rotation.GetValue().ToRotationMatrix(rotation);

	Matrix4x4 translation;
	translation.InitTranslation(Position.GetValue());

	Vector3 anchor = Anchor;
	local.InitTranslation(-anchor);
	local *= translation;
    local *= Matrix.GetValue();
	local *= rotation;
}

void Transform::CalcWorld( DirtyProperty<Transform*, Matrix4x4>::EventData& event )
{
	Matrix4x4& world = *event.Value;
	world = *Local.GetValue();
}

void Transform::CalcWorldInverse( DirtyProperty<Transform*, Matrix4x4>::EventData& event )
{
	Matrix4x4& inv = *event.Value;
	inv = World.GetValue()->Invert();
}

void Transform::HookOther( Transform* other )
{
	other->World.HasBecomeDirty += event_handler(this, &Transform::OtherWorldChanged);
}

void Transform::UnHookOther( Transform* other )
{
	other->World.HasBecomeDirty -= event_handler(this, &Transform::OtherWorldChanged);
}

void Transform::OtherWorldChanged( DirtyProperty<Transform*, Matrix4x4>* event )
{
	World.MakeDirty();
	WorldInverse.MakeDirty();
}
